package io.plus.server;

import drds.common.Clock;
import io.plus.interactive.AsynchronousSocketChannelContext;
import io.plus.interactive.Configuration;
import io.plus.interactive.Io;
import io.plus.interactive.collections.IpBlackList;
import io.plus.interactive.task.CloseCode;
import io.plus.interactive.user_interface.AioHandler;
import io.plus.utils.lock.ReadWriteLockSet;
import io.plus.utils.lock_capable_task.LockCapableTaskThreadPoolExecutor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.Set;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;

@Slf4j
@Data
public class ServerConfiguration extends Configuration {
    private AcceptCompletionHandler acceptCompletionHandler = null;
    private ServerAioHandler serverAioHandler = null;

    private Thread checkHeartbeatThread = null;
    private boolean needCheckHeartbeat = true;
    private boolean isShared = false;

    public ServerConfiguration(ServerAioHandler serverAioHandler) {
        this(null, serverAioHandler);
    }

    public ServerConfiguration(String name, ServerAioHandler serverAioHandler) {
        this(name, serverAioHandler, null, null);
    }

    public ServerConfiguration(ServerAioHandler serverAioHandler, LockCapableTaskThreadPoolExecutor tioExecutor, ThreadPoolExecutor groupExecutor) {
        this(null, serverAioHandler, tioExecutor, groupExecutor);
    }

    public ServerConfiguration(String name, ServerAioHandler serverAioHandler, LockCapableTaskThreadPoolExecutor tioExecutor,
                               ThreadPoolExecutor groupExecutor) {
        super(tioExecutor, groupExecutor);
        this.ipBlacklist = new IpBlackList(this);
        init(name, serverAioHandler, tioExecutor, groupExecutor);
    }

    private void init(String name, ServerAioHandler serverAioHandler, LockCapableTaskThreadPoolExecutor tioExecutor, ThreadPoolExecutor groupExecutor) {
        this.name = name;

        this.acceptCompletionHandler = new AcceptCompletionHandler();
        this.serverAioHandler = serverAioHandler;

        checkHeartbeatThread = new Thread(new Runnable() {
            @Override
            public void run() {
                //第一次先休息一下
                try {
                    Thread.sleep(1000 * 10);
                } catch (InterruptedException e1) {
                    log.error(e1.toString(), e1);
                }

                while (needCheckHeartbeat && !isStopped()) {
                    try {
                        Thread.sleep(heartbeatTimeout);
                    } catch (InterruptedException e1) {
                        log.error(e1.toString(), e1);
                    }
                    ReadWriteLockSet<AsynchronousSocketChannelContext> connections = ServerConfiguration.this.connections;
                    Set<AsynchronousSocketChannelContext> set = null;

                    ReadLock readLock = connections.getReadLock();
                    readLock.lock();
                    try {

                        set = connections.getObject();

                        for (AsynchronousSocketChannelContext asynchronousSocketChannelContext : set) {

                            long compareTime = Math.max(asynchronousSocketChannelContext.asynchronousSocketChannelState.latestTimeOfReceivedByte, asynchronousSocketChannelContext.asynchronousSocketChannelState.latestTimeOfSentPacket);
                            long currtime = Clock.currentTimeMillis;
                            long interval = currtime - compareTime;

                            boolean needRemove = false;
                            if (asynchronousSocketChannelContext.heartbeatTimeout != null && asynchronousSocketChannelContext.heartbeatTimeout > 0) {
                                needRemove = interval > asynchronousSocketChannelContext.heartbeatTimeout;
                            } else {
                                needRemove = interval > heartbeatTimeout;
                            }

                            if (needRemove) {
                                //if (!ServerConfiguration.this.serverAioListener.onHeartbeatTimeout(asynchronousSocketChannelContext, interval, asynchronousSocketChannelContext.asynchronousSocketChannelState.heartbeatTimeoutCount.incrementAndGet())) {
                                {
                                    log.info("{}, {} ms没有收发消息", asynchronousSocketChannelContext, interval);
                                    asynchronousSocketChannelContext.setCloseCode(CloseCode.HEARTBEAT_TIMEOUT);
                                    Io.remove(asynchronousSocketChannelContext, interval + " ms没有收发消息");
                                }
                            }
                        }
                    } catch (Throwable e) {
                        log.error("", e);
                    } finally {
                        try {
                            readLock.unlock();
                            //if (debug)
                        } catch (Throwable e) {
                            log.error("", e);
                        }
                    }
                }

            }
        }, "io-check heartbeat-" + id + "-" + name);
        checkHeartbeatThread.setDaemon(true);
        checkHeartbeatThread.setPriority(Thread.MIN_PRIORITY);
        checkHeartbeatThread.start();
    }


    @Override
    public AioHandler getAioHandler() {
        return this.getServerAioHandler();
    }


    @Override
    public boolean isServer() {
        return true;
    }


}
